package com.zf.yichat.service.impl;

import com.github.pagehelper.PageHelper;
import com.zf.yichat.IntegralInfoDto;
import com.zf.yichat.dto.*;
import com.zf.yichat.mapper.UserBalanceMapper;
import com.zf.yichat.mapper.UserExchangeBalanceMapper;
import com.zf.yichat.mapper.UserIntegralDetailMapper;
import com.zf.yichat.mapper.UserMapper;
import com.zf.yichat.model.*;
import com.zf.yichat.service.BalanceService;
import com.zf.yichat.service.SysDictService;
import com.zf.yichat.service.UserIntegralService;
import com.zf.yichat.service.UserService;
import com.zf.yichat.utils.YiChatMsgCode;
import com.zf.yichat.utils.common.DateUtils;
import com.zf.yichat.utils.common.DtoChangeUtils;
import com.zf.yichat.utils.common.SysInternPool;
import com.zf.yichat.utils.response.FsPage;
import com.zf.yichat.utils.response.FsResponse;
import com.zf.yichat.utils.response.FsResponseGen;
import com.zf.yichat.vo.BalanceType;
import com.zf.yichat.vo.DictKey;
import com.zf.yichat.vo.IntegralType;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.hibernate.validator.internal.util.Contracts;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.*;

/**
 * 一句话描述功能
 *
 * @author fengsong
 * @date create in 14:10 2020/3/25 2020
 */
@Service
public class UserIntegralServiceImpl implements UserIntegralService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private SysDictService sysDictService;

    @Autowired
    private UserIntegralDetailMapper userIntegralDetailMapper;

    @Autowired
    private UserService userService;

    @Autowired
    private BalanceService balanceService;

    @Autowired
    private UserExchangeBalanceMapper exchangeBalanceMapper;
    @Autowired
    private UserBalanceMapper userBalanceMapper;


    @Override
    public FsResponse getIntegral(IntegralType type, Long userId, String referId) {


        switch (type) {
            //签到 每天只能签到一次
            case SIGN:
                UserIntegralDetail detail = selectLastByType(type, userId);
                if (Objects.nonNull(detail) && detail.getCtime().getTime() > DateUtils.parse(DateUtils.formatCurrentDate("yyyy-MM-dd") + " 00:00:00").getTime()) {
                    return FsResponseGen.success(YiChatMsgCode.INTEGRAL_SIGN_REPEAT);
                }
                //查询配置的签到获取积分
                Integer preSign = NumberUtils.toInt(sysDictService.selectOne(DictKey.integral_sign).getValue());
                updateDetail(IntegralType.SIGN, null, preSign, userId);
                break;
            case INVITE:
                //查询邀请人获取积分
                Integer invite = NumberUtils.toInt(sysDictService.selectOne(DictKey.integral_invite).getValue());
                //被邀请人获取积分 referID 此时为被邀请人
                updateDetail(IntegralType.INVITE, referId, invite, userId);
                break;

            default:
        }

        if (type.getVal() == IntegralType.SHARE_QQ_AROUND.getVal()
                || type.getVal() == IntegralType.SHARE_QQ_FREIND.getVal()
                || type.getVal() == IntegralType.SHARE_WX_AROUND.getVal()
                || type.getVal() == IntegralType.SHARE_WX_FRIENDS.getVal()) {

            Integer share = NumberUtils.toInt(sysDictService.selectOne(DictKey.integral_share).getValue());
            Integer limitShare = NumberUtils.toInt(sysDictService.selectOne(DictKey.integral_share_limit).getValue());

            //如果当前分享已超过次数 则不添加
            Integer count = countDayByType(type, userId);
            if (count < limitShare) {
                updateDetail(type, referId, share, userId);
            }
        }

        return info(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDetail(IntegralType type, String referId, Integer score, Long userId) {

        //增加记录
        UserIntegralDetail detail = new UserIntegralDetail();
        detail.setIntegral(score);
        detail.setReferType(type.getVal());
        detail.setMemo(type.getDesc());
        detail.setUserId(userId);
        detail.setReferId(referId);

        userIntegralDetailMapper.insertSelective(detail);

        //增加积分值
        userMapper.addIntegral(score, userId);

    }

    @Override
    public UserIntegralDetail selectLastByType(IntegralType type, Long userId) {
        Example example = new Example(UserIntegralDetail.class);
        example.createCriteria().andEqualTo("userId", userId).andEqualTo("referType", type.getVal());
        example.setOrderByClause(" id desc limit 1");
        return userIntegralDetailMapper.selectOneByExample(example);
    }

    @Override
    public int countDayByType(IntegralType type, Long userId) {
        Example example = new Example(UserIntegralDetail.class);
        example.createCriteria().andEqualTo("userId", userId)
                .andEqualTo("referType", type.getVal())
                .andGreaterThanOrEqualTo("ctime", DateUtils.formatCurrentDate("yyyy-MM-dd") + DateUtils.TIME_START_SUFFIX)
                .andLessThan("ctime", DateUtils.formatCurrentDate("yyyy-MM-dd") + DateUtils.TIME_END_SUFFIX);

        return userIntegralDetailMapper.selectCountByExample(example);
    }

    @Override
    public FsResponse detailInfo(FsPage init, Long userId) {
        Example example = new Example(UserIntegralDetail.class);
        example.createCriteria().andEqualTo("userId", userId);
        example.setOrderByClause(" id desc");
        PageHelper.startPage(init.getPageNo(), init.getPageSize());
        return DtoChangeUtils.getPageList(userIntegralDetailMapper.selectByExample(example), v -> {
            IntegralDetailListDto dto = new IntegralDetailListDto();
            dto.setMemo(v.getMemo() + " : " + v.getIntegral() + "积分");
            dto.setIntegral(v.getIntegral());
            dto.setTimeDesc(DateUtils.formatDate(v.getCtime(), "yyyy-MM-dd HH:mm:ss"));
            return dto;
        });
    }

    @Override
    public FsResponse info(Long userId) {

        IntegralInfoDto dto = new IntegralInfoDto();
        dto.setIntegral(userService.selectById(userId).getIntegral());

        //根据当前积分 划分登记
        dto.setLevel(selectLevel(dto.getIntegral()).getName());

        Example example = new Example(UserIntegralDetail.class);
        example.createCriteria().andEqualTo("userId", userId);
        example.setOrderByClause(" id desc limit 1");

        dto.setLastMemo(Optional.ofNullable(userIntegralDetailMapper.selectOneByExample(example)).map(v -> v.getMemo() + "获取" + v.getIntegral() + "积分").orElse(""));

        dto.setRulecontent(sysDictService.selectOne(DictKey.integral_content).getMemo());
        dto.setTitle(sysDictService.selectOne(DictKey.share_title).getMemo());
//        dto.setShareIntegral(Optional.ofNullable(countShare(userId)).orElse(0));
        dto.setShareIntegral(NumberUtils.toInt(sysDictService.selectOne(DictKey.integral_share).getValue()));
        dto.setShareDes(sysDictService.selectOne(DictKey.share_content).getMemo());
        dto.setWebUrl(sysDictService.selectOne(DictKey.share_url).getMemo());

        return FsResponseGen.successData(dto);
    }

    @Override
    public SysDictData selectLevel(Integer integral) {

        List<SysDictData> list = sysDictService.selectData(DictKey.integral_level);


        for (SysDictData data : list) {
            if (integral < Long.parseLong(data.getValue())) {
                return data;
            }

        }

        return null;
    }

    @Override
    public Integer countShare(Long userId) {
        return userIntegralDetailMapper.sumShare(userId);
    }

    @Override
    public void giveIntegralForType(Long userId, String type) {

        // 注册类型
        if (User.REGISTER_TYPE.equals(type)) {
            Example exampleRegister = new Example(UserIntegralDetail.class);
            Example.Criteria criteriaRegister = exampleRegister.createCriteria();
            criteriaRegister.andEqualTo("userId", userId).andEqualTo("referType", IntegralType.REGISTER_CONSUME.getVal());
            List<UserIntegralDetail> registerList = userIntegralDetailMapper.selectByExample(exampleRegister);
            Contracts.assertTrue(null == registerList || registerList.size() == 0, "注册赠送积分已领取，请勿重复！");

            SysDict sysDict = sysDictService.selectOne(DictKey.user_register_give_integral);
            Integer integral = 0;
            if (null == sysDict) {
                integral = 0;
            }else {
                integral = Integer.valueOf(sysDict.getValue());
            }

            updateDetail(IntegralType.REGISTER_CONSUME, userId + ":" + User.REGISTER_TYPE, integral, userId);

        }
        // 实名认证
        else if (User.REAL_NAME_TYPE.equals(type)) {
            Example exampleRealName = new Example(UserIntegralDetail.class);
            Example.Criteria criteriaRealName = exampleRealName.createCriteria();
            criteriaRealName.andEqualTo("userId", userId).andEqualTo("referType", IntegralType.REAL_NAME_CONSUME.getVal());
            List<UserIntegralDetail> realNameList = userIntegralDetailMapper.selectByExample(exampleRealName);
            Contracts.assertTrue(null == realNameList || realNameList.size() == 0, "实名认证赠送积分已领取，请勿重复！");

            SysDict sysDict = sysDictService.selectOne(DictKey.user_real_name_give_integral);
            Integer integral = 0;
            if (null == sysDict) {
                integral = 0;
            }
            else {
                integral = Integer.valueOf(sysDict.getValue());
            }


            updateDetail(IntegralType.REAL_NAME_CONSUME, userId  + ":" + User.REAL_NAME_TYPE, integral, userId);

        }
        else if (User.BIND_CARD_TYPE.equals(type)){
            Example exampleCard = new Example(UserIntegralDetail.class);
            Example.Criteria criteriaCard = exampleCard.createCriteria();
            criteriaCard.andEqualTo("userId", userId).andEqualTo("referType", IntegralType.BIND_CARD_CONSUME.getVal());
            List<UserIntegralDetail> cardList = userIntegralDetailMapper.selectByExample(exampleCard);
            Contracts.assertTrue(null == cardList || cardList.size() == 0, "绑卡赠送积分已领取，请勿重复！");

            // 绑卡
            SysDict sysDict = sysDictService.selectOne(DictKey.user_bind_card_give_integral);

            Integer integral = 0;
            if (null == sysDict) {
                integral = 0;
            }
            else {
                integral = Integer.valueOf(sysDict.getValue());
            }

            updateDetail(IntegralType.BIND_CARD_CONSUME, userId  + ":" + User.BIND_CARD_TYPE, integral, userId);
        }
        else {
            Contracts.assertTrue(true, "赠送积分类型错误！");
        }
    }

    @Override
    public FsResponse userEnergyBlockDetails(FsPage init, Long userId) {
        Example example = new Example(UserIntegralDetail.class);
        example.createCriteria().andEqualTo("userId", userId);
        example.setOrderByClause(" id desc");
        PageHelper.startPage(init.getPageNo(), init.getPageSize());
        return DtoChangeUtils.getPageList(userIntegralDetailMapper.selectByExample(example), v -> {
            IntegralDetailListDto dto = new IntegralDetailListDto();
            dto.setMemo(v.getMemo() + " : " + v.getIntegral() + "g");
            dto.setIntegral(v.getIntegral());
            dto.setTimeDesc(DateUtils.formatDate(v.getCtime(), "yyyy-MM-dd HH:mm:ss"));
            return dto;
        });
    }

    @Override
    public FsResponse exchangeBalanceInitialization(Long userId) {

        // 查询用户当前积分值
        User user = userService.selectById(userId);
        Integer integral = user.getIntegral();
        BigDecimal userIntegral = new BigDecimal(integral);

        SysDict sysDict = sysDictService.selectOne(DictKey.user_integral_exchange_balance_ratio);
        // 默认兑换比例为1
        BigDecimal ratio = new BigDecimal(1);
        if (null != sysDict) {
            ratio = new BigDecimal(sysDict.getValue());
        }

        // 按照比例算出可兑换的余额
        BigDecimal balance = userIntegral.multiply(ratio);

        // 配置的兑换规则
        SysDict roleDict = sysDictService.selectOne(DictKey.user_integral_exchange_balance_rule);
        String role = "暂无配置";
        if (null != roleDict) {
            role = roleDict.getMemo();
        }

        IntegralExchangeBalanceDto dto = new IntegralExchangeBalanceDto();
        dto.setIntegral(userIntegral);
        dto.setExchangeBalance(balance);
        dto.setExchangeRule(role);
        return FsResponseGen.successData(dto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FsResponse exchangeBalance(Long userId, BigDecimal exchangeAmount) {
        synchronized (SysInternPool.INSTANCE.internUid(userId)) {
            // 计算积分是否满足兑换的余额
            SysDict sysDict = sysDictService.selectOne(DictKey.user_integral_exchange_balance_ratio);
            // 默认兑换比例为1
            BigDecimal ratio = new BigDecimal(1);
            if (null != sysDict) {
                ratio = new BigDecimal(sysDict.getValue());
            }

            BigDecimal integral = exchangeAmount.divide(ratio);

            User user = userService.selectById(userId);
            BigDecimal userIntegral = new BigDecimal(user.getIntegral());
            if (userIntegral.compareTo(integral) < 0) {
                return FsResponseGen.failMsg("用户积分不足，无法兑换" + exchangeAmount + "元");
            }

            // 新增兑换记录
            UserExchangeBalance exchangeBalance = new UserExchangeBalance();
            exchangeBalance.setUserId(userId);
            exchangeBalance.setIntegral(integral.intValue());
            exchangeBalance.setBalance(exchangeAmount);
            exchangeBalance.setRatio(ratio);
            exchangeBalance.setCreateTime(new Date());
            exchangeBalanceMapper.insertSelective(exchangeBalance);

            Long exchangeBalanceId = exchangeBalance.getId();

            // 增加用户余额
            balanceService.update(userId, BalanceType.INTEGRAL_EXCHANGE_BALANCE, exchangeAmount, exchangeBalanceId, BalanceType.INTEGRAL_EXCHANGE_BALANCE.getDesc());

            // 更新积分
            updateDetail(IntegralType.INTEGRAL_EXCHANGE_BALANCE, exchangeBalanceId.toString(), -integral.intValue(), userId);

            return exchangeBalanceInitialization(userId);
        }
    }

    @Override
    public FsResponse exchangeBalanceRecordList(Integer pageNo, Integer pageSize, Long userId) {

        Example example = new Example(UserExchangeBalance.class);
        example.createCriteria().andEqualTo("userId", userId);
        example.setOrderByClause("create_time desc");
        PageHelper.startPage(pageNo, pageSize);
        return DtoChangeUtils.getPageList(exchangeBalanceMapper.selectByExample(example), exchangeBalance -> {
            UserExchangeBalance dto = new UserExchangeBalance();
            BeanUtils.copyProperties(exchangeBalance, dto);
            return dto;
        });
    }

    @Override
    public FsResponse queryExchangeBalanceDetails(Long userId) {

        Example example = new Example(UserExchangeBalance.class);
        example.createCriteria().andEqualTo("userId", userId);
        Integer exchangedNum = exchangeBalanceMapper.selectUserExchangedNum(userId);
        if (null == exchangedNum) {
            exchangedNum = 0;
        }

        User user = userService.selectById(userId);
        Integer integral = user.getIntegral();

        UserExchangeBalanceDto balanceDto = new UserExchangeBalanceDto();
        balanceDto.setExchangedNum(exchangedNum);
        balanceDto.setIntegral(integral + exchangedNum);
        balanceDto.setUnExchangeNum(integral);
        return FsResponseGen.successData(balanceDto);
    }

    @Override
    public FsResponse queryLowCarbonDetails(FsPage page, Long userId, Integer type, String ctime) {

        Example example = new Example(UserIntegralDetail.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("userId", userId);
        if (StringUtils.isNotBlank(ctime)) {
            criteria.andCondition("DATE_FORMAT(ctime,'%Y-%m-%d') = ", ctime);
        }

        if (Objects.nonNull(type)) {
            //支出
            if (type == 0) {
                criteria.andIn("referType", Arrays.asList(
                        IntegralType.INTEGRAL_EXCHANGE_BALANCE.getVal()
                ));
            }
            //收入
            else {
                criteria.andIn("referType", Arrays.asList(
                        IntegralType.SIGN.getVal(),
                        IntegralType.ANSWER_QUESTION.getVal(),
                        IntegralType.REAL_NAME_CONSUME.getVal(),
                        IntegralType.REGISTER_CONSUME.getVal(),
                        IntegralType.PLANT_TREE.getVal()));
            }
        }
        // 查询全部类型-收入和支出
        else {
            criteria.andIn("referType", Arrays.asList(
                    IntegralType.INTEGRAL_EXCHANGE_BALANCE.getVal(),
                    IntegralType.SIGN.getVal(),
                    IntegralType.REAL_NAME_CONSUME.getVal(),
                    IntegralType.REGISTER_CONSUME.getVal(),
                    IntegralType.ANSWER_QUESTION.getVal(),
                    IntegralType.PLANT_TREE.getVal()
                    ));
        }

        example.setOrderByClause("ctime desc");
        PageHelper.startPage(page.getPageNo(), page.getPageSize());
        return DtoChangeUtils.getPageList(userIntegralDetailMapper.selectByExample(example), v -> {
            IntegralDetailListDto dto = new IntegralDetailListDto();
            dto.setMemo(v.getMemo() + " : " + v.getIntegral() + "g");
            dto.setIntegral(v.getIntegral());
            dto.setTimeDesc(DateUtils.formatDate(v.getCtime(), "yyyy-MM-dd HH:mm:ss"));
            return dto;
        });
    }

    @Override
    public FsResponse queryAccumulated(Long userId) {

        // 查询累计获得的碳能量
        Example example = new Example(UserIntegralDetail.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("userId", userId);
        List<UserIntegralDetail> integralDetails = userIntegralDetailMapper.selectByExample(example);

        Integer accumulatedIntegral = 0;
        for (UserIntegralDetail detail : integralDetails) {
            Integer integral = detail.getIntegral();
            if (integral > 0) {
                //            integral = Math.abs(integral);
                accumulatedIntegral += integral;
            }

        }

        // 查询累计兑换的金额

        Example exchangeExample = new Example(UserExchangeBalance.class);
        Example.Criteria exchangeCriteria = exchangeExample.createCriteria();
        exchangeCriteria.andEqualTo("userId", userId);
        List<UserExchangeBalance> exchangeBalances = exchangeBalanceMapper.selectByExample(exchangeExample);

        BigDecimal accumulatedBalance = new BigDecimal(0);
        for (UserExchangeBalance balance : exchangeBalances) {
            BigDecimal exchangeBalance = balance.getBalance();
            accumulatedBalance = accumulatedBalance.add(exchangeBalance);
        }

        // 查询用户当前余额
        Example exampleBalance = new Example(UserBalance.class);
        Example.Criteria criteriaBalance = exampleBalance.createCriteria();
        criteriaBalance.andEqualTo("userId", userId);
        UserBalance userBalance = userBalanceMapper.selectOneByExample(exampleBalance);

        BigDecimal incomeBalance = new BigDecimal(0);
        if (null != userBalance) {
            incomeBalance = userBalance.getIncomeBalance();
        }
        UserAccumulatedDto userAccumulatedDto = new UserAccumulatedDto();
        userAccumulatedDto.setAccumulatedBalance(accumulatedBalance);
        userAccumulatedDto.setAccumulatedIntegral(accumulatedIntegral);
        userAccumulatedDto.setIncomeBalance(incomeBalance);
        return FsResponseGen.successData(userAccumulatedDto);
    }
}
